home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2007 December
/
PCWKCD1207B.iso
/
Blogowanie poza sfera
/
Flock 1.0 beta
/
flock-1.0RC3.en-US.win32.exe
/
flock
/
components
/
flockPhotoAPIManager.js
< prev
next >
Wrap
Text File
|
2007-10-18
|
32KB
|
906 lines
// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2007
// http://flock.com
//
// This file may be used under the terms of of the
// GNU General Public License Version 2 or later (the "GPL"),
// http://www.gnu.org/licenses/gpl.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// END FLOCK GPL
const Cc = Components.classes;
const Ci = Components.interfaces;
const FLOCK_PHOTO_API_MANAGER_CID = Components.ID('{18e27f2e-c99c-4915-9907-1a9fc0780ed6}');
const nsISupports = Components.interfaces.nsISupports;
const nsIClassInfo = Components.interfaces.nsIClassInfo;
const nsIFactory = Components.interfaces.nsIFactory;
const nsIProperties = Components.interfaces.nsIProperties;
const nsILocalFile = Components.interfaces.nsILocalFile;
const nsIFile = Components.interfaces.nsIFile;
const nsIIOService = Components.interfaces.nsIIOService;
const nsIFileProtocolHandler = Components.interfaces.nsIFileProtocolHandler;
const nsIPreferenceService = Components.interfaces.nsIPrefBranch;
const flockIPhotoAPIManager = Components.interfaces.flockIPhotoAPIManager;
const flockIPhotoPeopleService = Components.interfaces.flockIPhotoPeopleService;
const flockIPollingService = Components.interfaces.flockIPollingService;
const flockIMigratable = Components.interfaces.flockIMigratable;
const FLOCK_PHOTO_API_MANAGER_CONTRACTID = '@flock.com/photo-api-manager;1?';
const FLOCK_PHOTO_CONTRACTID = '@flock.com/photo;1';
const DIRECTORY_SERVICE_CONTRACTID = '@mozilla.org/file/directory_service;1';
const LOCAL_FILE_CONTRACTID = '@mozilla.org/file/local;1';
const PREFERENCES_CONTRACTID = '@mozilla.org/preferences-service;1';
const IO_SERVICE_CONTRACTID = '@mozilla.org/network/io-service;1';
const RDFCU_CONTRACTID = '@mozilla.org/rdf/container-utils;1';
const MYWORLD_SERVICE_CONTRACTID = '@flock.com/myworld-service;1';
const RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
const FLOCK_NS = "http://flock.com/rdf#";
const NC_NS = "http://home.netscape.com/NC-rdf#";
/* for Cardinal migration */
const OLD_PEOPLE_PHOTO_RDF_FILE = 'flock_people_photo.rdf';
const OLD_PEOPLE_PHOTO_RDF_FILE_RELIC = 'flock_people_photo_old.rdf';
const LIST_ACCOUNTS_ROOT = 'urn:flock:people:photo:lists:accounts';
const MEDIA_FAVES_ROOT = 'urn:media:favorites';
const RDFS = Components.classes['@mozilla.org/rdf/rdf-service;1']
.getService (Components.interfaces.nsIRDFService);
const IOS = Components.classes[IO_SERVICE_CONTRACTID]
.getService(Components.interfaces.nsIIOService);
const RDFCU = Components.classes[RDFCU_CONTRACTID]
.getService(Components.interfaces.nsIRDFContainerUtils);
function flockPhotoAPIManager() {
this.processingQueue = {};
this.mPrefService = Components.classes[PREFERENCES_CONTRACTID].getService(nsIPreferenceService);
this.mLogger = Components.classes["@flock.com/logger;1"].createInstance(Components.interfaces.flockILogger);
this.mLogger.init("photo");
this.mLogger.info("starting up...");
var inst = this;
var timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
var timerFunc = {
notify: function(aTimer) {
inst.updateStates();
},
}
timer.initWithCallback(timerFunc, 5 * 1000, 1);
}
//flockIMigratable
flockPhotoAPIManager.prototype.__defineGetter__("migrationName",
function getter_migrationName() {
return "Photo Accounts";
});
flockPhotoAPIManager.prototype.needsMigration =
function needsMigration(oldVersion) {
this.mLogger.info(".needsMigration('" + oldVersion + "')\n");
if (oldVersion.substr(0, 3) == "0.7") { // migration from Cardinal (0.7.x)
var oldPeoplePhotoFile = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
oldPeoplePhotoFile.append(OLD_PEOPLE_PHOTO_RDF_FILE);
if (oldPeoplePhotoFile.exists()) {
this.mLogger.info("needs migration from 0.7.x\n");
return true;
}
return false;
} else if (oldVersion.substr(0, 3) == "0.9") { // migration from 0.9.X
this.mLogger.info("needs migration from 0.9.X\n");
return true;
} else {
return false;
}
}
flockPhotoAPIManager.prototype.startMigration =
function startMigration(oldVersion, aFlockMigrationProgressListener) {
this.mLogger.info(".startMigration('" + oldVersion + "', 'aFlockMigrationProgressListener')\n");
var ctxt = {
oldVersion: oldVersion,
listener: aFlockMigrationProgressListener
};
if (oldVersion.substr(0, 3) == "0.7") { // migration from Cardinal (0.7.x)
var oldPeoplePhotoFile = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
oldPeoplePhotoFile.append(OLD_PEOPLE_PHOTO_RDF_FILE);
ctxt.oldPeoplePhotoFile = oldPeoplePhotoFile;
if (oldPeoplePhotoFile.exists())
ctxt.listener.onUpdate(0, "Migrating photo people");
} else if (oldVersion.substr(0, 3) == "0.9") { // Migration from 0.9.x
ctxt.listener.onUpdate(0, "Migrating account and media queries");
}
return { wrappedJSObject: ctxt };
}
flockPhotoAPIManager.prototype.finishMigration =
function finishMigration(ctxtWrapper) {
}
flockPhotoAPIManager.prototype.doMigrationWork =
function doMigrationWork(ctxtWrapper) {
var ctxt = ctxtWrapper.wrappedJSObject;
var oldVersion = ctxt.oldVersion;
if (oldVersion.substr(0, 3) == "0.7") {
if (!ctxt.oldPeoplePhotoFile.exists()) {
return false;
}
if (!ctxt.photoMigrator) {
ctxt.photoMigrator = this._migratePhotoPeople(ctxt);
}
if (ctxt.photoMigrator.next()) {
ctxt.photoMigrator = null;
}
return Boolean(ctxt.photoMigrator);
} else if (oldVersion.substr(0, 3) == "0.9") {
this._migrate09xPhotoAccount();
this._migrateMediaQueries(oldVersion);
return false;
}
}
// josh changed latestSeq property of mediaqueries from
// an int to a string - we need to migrate this type change
flockPhotoAPIManager.prototype._migrateMediaQueries =
function _migrateMediaQueries(aOldVersion)
{
this.mLogger.info("._migrateMediaQueries()\n");
var dataFileDS = RDFS.GetDataSource("rdf:flock-favorites");
// get all media query rdf nodes
var mqResource = RDFS.GetResource(FLOCK_NS+"CoopType");
var mqLiteral = RDFS.GetResource(NC_NS+"MediaQuery");
var mediaQueries = dataFileDS.GetSources(mqResource, mqLiteral, true);
function getTargetInt(aSource, aArcName) {
var target = dataFileDS.GetTarget(aSource, RDFS.GetResource(FLOCK_NS+aArcName), true);
target instanceof Components.interfaces.nsIRDFInt;
return target;
};
function getTargetLiteral(aSource, aArcName) {
var target = dataFileDS.GetTarget(aSource,
RDFS.GetResource(FLOCK_NS+aArcName),
true);
target instanceof Components.interfaces.nsIRDFLiteral;
return target;
};
function getTargetDate(aSource, aArcName) {
var target = dataFileDS.GetTarget(aSource,
RDFS.GetResource(FLOCK_NS+aArcName),
true);
target instanceof Components.interfaces.nsIRDFDate;
return target;
};
while (mediaQueries && mediaQueries.hasMoreElements()) {
var mediaQuery = mediaQueries.getNext();
mediaQuery.QueryInterface(Components.interfaces.nsIRDFResource);
var subject = RDFS.GetResource(mediaQuery.Value);
// For latestSeq, replace old int value with string if migrating
// from 0.9.0.x
if (aOldVersion.substr(0, 5) == "0.9.0") {
var latestSeqInt = getTargetInt(mediaQuery, "latestSeq");
var predicate = RDFS.GetResource(FLOCK_NS+"latestSeq");
var latestSeqString = RDFS.GetLiteral(latestSeqInt.Value);
dataFileDS.Change(subject, predicate, latestSeqInt, latestSeqString);
}
// Migrate the favicon url
var iconPred = RDFS.GetResource(FLOCK_NS+"favicon");
var faviconLit = getTargetLiteral(mediaQuery, "favicon");
var svcShortNameLit = getTargetLiteral(mediaQuery, "svc");
var icon = this.getAPIFromShortname(svcShortNameLit.Value).icon;
var iconLit = RDFS.GetLiteral(icon);
// Don't overwrite binary hardcoded favicons
if (faviconLit.Value.match(/^chrome:/)) {
dataFileDS.Change(subject, iconPred, faviconLit, iconLit);
}
var isPollable = getTargetLiteral(mediaQuery, "isPollable");
if (isPollable.Value == "true") {
// Force refresh on media query
dataFileDS.Change(subject,
RDFS.GetResource(FLOCK_NS + "nextRefresh"),
getTargetDate(mediaQuery, "nextRefresh"),
RDFS.GetDateLiteral((new Date()).getTime()*1000));
}
}
}
flockPhotoAPIManager.prototype._migrate09xPhotoAccount =
function flockPhotoAPIManager__migrate09xPhotoAccount()
{
this.mLogger.info("._migrate09xPhotoAccount()");
var acUtils = Cc["@flock.com/account-utils;1"]
.getService(Ci.flockIAccountUtils);
var _coopfile = "chrome://flock/content/common/load-faves-coop.js";
var _coop = Cc["@flock.com/singleton;1"]
.getService(Ci.flockISingleton)
.getSingleton(_coopfile)
.wrappedJSObject;
var accounts = acUtils.getAccountsByInterface("flockIMediaWebService");
while (accounts.hasMoreElements()) {
var account = accounts.getNext();
account = account.QueryInterface(Ci.flockIWebServiceAccount);
this.mLogger.debug("_migrate09xPhotoAccount -- migrating " + account.urn);
var c_acct = _coop.get(account.urn);
var service = Cc[c_acct.serviceId].getService(Ci.flockIWebService);
service.migrateAccount(c_acct.accountId, c_acct.name);
}
}
flockPhotoAPIManager.prototype._migratePhotoPeople =
function _migratePhotoPeople(ctxt)
{
// Load old datasource
var oldPhotoPeepsDS = RDFS.GetDataSourceBlocking(IOS.newFileURI(ctxt.oldPeoplePhotoFile).spec);
var acctsRoot = RDFS.GetResource(LIST_ACCOUNTS_ROOT);
var streamsRoot = RDFS.GetResource("urn:flock:people:photo:lists:watched");
var getValue = function (aSource, aArcName) {
var target = oldPhotoPeepsDS.GetTarget(aSource, RDFS.GetResource(FLOCK_NS+aArcName), true);
target instanceof Components.interfaces.nsIRDFLiteral;
return target.Value;
};
// Migrate accounts
var accounts = RDFCU.MakeSeq(oldPhotoPeepsDS, acctsRoot).GetElements();
while (accounts && accounts.hasMoreElements()) {
var account = accounts.getNext();
account.QueryInterface(Components.interfaces.nsIRDFResource);
var username = getValue(account, "username");
var apiShortName = getValue(account, "apiShortName");
var id = getValue(account, "id");
var api = this.getAPIFromShortname(apiShortName);
api.migrateAccount(id, username);
}
// Load new datasource
var _coop = Components.classes["@flock.com/singleton;1"]
.getService(Components.interfaces.flockISingleton)
.getSingleton("chrome://flock/content/common/load-faves-coop.js")
.wrappedJSObject;
var mediaFavesURN = MEDIA_FAVES_ROOT;
var mediaFaves = _coop.get(mediaFavesURN);
if (!mediaFaves) {
mediaFaves = new _coop.Folder(mediaFavesURN);
_coop.favorites_root.children.add(mediaFaves);
}
// Migrate favorite photo streams
var streams = RDFCU.MakeSeq(oldPhotoPeepsDS, streamsRoot).GetElements();
while (streams && streams.hasMoreElements()) {
var stream = streams.getNext();
stream.QueryInterface(Components.interfaces.nsIRDFResource);
var apiShortName = getValue(stream, "apiShortName");
var id = getValue(stream, "id");
var mediaqueryURN = MEDIA_FAVES_ROOT+apiShortName+":user:"+id+"|username:"+getValue(stream, "username");
var mediaquery = new _coop.MediaQuery(
mediaqueryURN,
{
serviceId: FLOCK_PHOTO_API_MANAGER_CONTRACTID,
service: apiShortName,
favicon: this.getAPIFromShortname(apiShortName).iconUrl,
query: "user:"+id+"|username:"+getValue(stream, "username"),
name: getValue(stream, "username"),
isPollable: true
}
);
mediaFaves.children.add(mediaquery);
}
// rename the old people photo file
ctxt.oldPeoplePhotoFile.moveTo(null, OLD_PEOPLE_PHOTO_RDF_FILE_RELIC);
yield true;
}
//////////////////////////////////////////////////////////////////////////////
// Implementation
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
flockPhotoAPIManager.prototype.mStates = {};
flockPhotoAPIManager.prototype.mListeners = new Array();
flockPhotoAPIManager.prototype.addListener = function(aListener) {
if (aListener == null) {
throw "Listener is null!!";
}
this.mListeners.push(aListener);
}
flockPhotoAPIManager.prototype.updateStates = function() {
for(var p in this.mStates) {
var shortName = p;
var state = this.mStates[p];
var api = this.getAPIFromShortname(p);
var newState = api.authState;
if(newState != state) {
this.notify(api);
}
this.mStates[p] = newState;
}
}
flockPhotoAPIManager.prototype.notify = function(aService) {
for(var i=0;i<this.mListeners.length;++i) {
this.mListeners[i].onAPIStateChange(aService);
}
}
flockPhotoAPIManager.prototype.doLogin = function(aAccountURN) {
// TODO: MAYBE FIXME (CDC):
// I changed the param for this function from aShortname to aAccountURN
// ... but I don't think this is actually called from anywhere so for now
// I'm gonna just throw NOT_IMPLEMENTED instead of fixing it to handle the
// new parameter. If it breaks things, I owe the first person who notices
// it a bubble tea.
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
var inst = this;
var myListener = {
onAuth: function() {
inst.notify(service);
inst.setDefaultService(service.shortName);
},
onError: function(aError) {
for (var i=0; i < inst.mListeners.length; i++) {
aError.QueryInterface(Components.interfaces.flockIError);
try {
var theError = {};
theError.errorCode = aError.errorCode;
theError.serviceErrorCode = aError.serviceErrorCode;
theError.serviceErrorString = aError.serviceErrorString;
theError.errorString = aError.errorString;
inst.mListeners[i].onError(theError);
} catch (ex) {
this.mLogger.error(ex);
}
}
},
}
var service = this.getAPIFromShortname(aShortname);
service.login(null, myListener);
this.notify(service);
}
flockPhotoAPIManager.prototype.doLogout = function(aShortname) {
var service = this.getAPIFromShortname(aShortname);
service.logout();
// TODO - maybe change the default service to something that is enabled ???
this.notify(service);
}
flockPhotoAPIManager.prototype.removeListener = function(aListener) {
for(var i=0;i<this.mListeners.length;++i) {
if(aListener==this.mListeners[i]) {
this.mListeners.splice(i,1);
break;
}
}
}
flockPhotoAPIManager.prototype.getAPIFromShortname = function(aShortname) {
// JMC - Special case, me!
if (aShortname == "preview") {
return this;
}
var catman = Cc["@mozilla.org/categorymanager;1"]
.getService(Ci.nsICategoryManager);
var webServices = [];
var e = catman.enumerateCategory("flockMediaProvider");
while (e.hasMoreElements()) {
var entry = e.getNext().QueryInterface(Ci.nsISupportsCString);
if (!entry) {
continue;
}
var contractID = catman.getCategoryEntry("flockMediaProvider", entry.data);
var svc = Cc[contractID].getService(Ci.flockIWebService);
if (svc.shortName == aShortname) {
return svc;
}
}
return null;
}
function loadLibraryFromSpec(aSpec)
{
var loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader);
loader.loadSubScript(aSpec);
}
loadLibraryFromSpec("chrome://flock/content/common/aggregate.js");
flockPhotoAPIManager.prototype.supportsSearch = function (aQuery) {
return false;
}
flockPhotoAPIManager.prototype.search = function (aListener, aQuery, aCount, aPage) {
// JMC - PQ of all mediaquery objects with new stuff
var faves_coop = Components.classes['@flock.com/singleton;1']
.getService(Components.interfaces.flockISingleton)
.getSingleton("chrome://flock/content/common/load-faves-coop.js")
.wrappedJSObject;
// JMC - If it's a page =1 request, perform the search
// Otherwise, return the next batch from the cached results
if (aPage > 1) {
aListener.onSearchResult(this.myUnseenEnum);
} else {
var mediaQueries = faves_coop.MediaQuery.find({hasUnseenItems: true});
var streams = [];
for (x in mediaQueries) {
var mediaquery = mediaQueries[x];
streams.push(mediaquery.children.enumerate());
}
var aggUnSeen = filterStream( aggregatePhotoStreams( streams ), function(item) {
return item && item.unseen;
});
var inst = this;
this.myUnseenEnum = {
hasMoreElements : function() {
return this.mEnum.hasMoreElements();
},
getNext : function() {
var child = this.mEnum.getNext();
// JMC - Get the real flockIPhoto from the coop obj.
var svcName = child.getParent().service;
return inst.getAPIFromShortname(svcName).getPhotoFromRDFNode(child.id());
},
};
this.myUnseenEnum.mEnum = aggUnSeen;
aListener.onSearchResult(this.myUnseenEnum);
}
}
flockPhotoAPIManager.prototype.__defineGetter__("services", function () {
var ar = new Array();
var catman = Cc["@mozilla.org/categorymanager;1"]
.getService(Ci.nsICategoryManager);
var webServices = [];
var e = catman.enumerateCategory("flockMediaProvider");
while (e.hasMoreElements()) {
var entry = e.getNext().QueryInterface(Ci.nsISupportsCString);
if (!entry) {
continue;
}
var contractID = catman.getCategoryEntry("flockMediaProvider", entry.data);
var svc = Cc[contractID]
.getService(Ci.flockIWebService);
if (svc instanceof Ci.flockIMediaWebService) {
ar.push(svc);
}
}
var rval = {
getNext: function() {
var rval = ar.shift();
return rval;
},
hasMoreElements: function() {
return (ar.length>0);
},
}
return rval;
})
flockPhotoAPIManager.prototype.getPreferredServices = function() {
try {
var pref = this.mPrefService.getCharPref("flock.photo.preferredServices");
var ar = pref.split(",");
var rval = [];
for(var i=0;i<ar.length;++i) {
if(ar[i].length) rval.push(ar[i]);
}
return rval;
} catch(e) {
//debug(e);
debug("getPreferredServices: No preferred services found, returning an empty set\n");
return [];
}
}
flockPhotoAPIManager.prototype.setPreferredServices = function(aArray) {
var val = aArray.join(",");
var pref = this.mPrefService.setCharPref("flock.photo.preferredServices", val);
}
flockPhotoAPIManager.prototype.getDefaultService = function() {
try {
var pref = this.mPrefService.getCharPref("flock.photo.lastService");
if (pref && pref.length)
return this.getAPIFromShortname(pref);
} catch(e) {
return null;
}
}
flockPhotoAPIManager.prototype.setDefaultService = function(aShortname) {
try {
this.mPrefService.setCharPref("flock.photo.lastService", aShortname);
} catch(e) {
debug(e);
}
}
flockPhotoAPIManager.prototype.__defineGetter__('preferredServices', function () {
try {
var inst = this;
var ar = this.getPreferredServices();
var rval = {
getNext: function() {
var shortName = ar.shift();
var api = inst.getAPIFromShortname(shortName);
return api;
},
hasMoreElements: function() {
return (ar.length>0);
},
}
return rval;
} catch(e) {
debug(e);
}
})
flockPhotoAPIManager.prototype.__defineGetter__("hasNewMedia", function () {
var faves_coop = Components.classes['@flock.com/singleton;1']
.getService(Components.interfaces.flockISingleton)
.getSingleton("chrome://flock/content/common/load-faves-coop.js")
.wrappedJSObject;
var mediaFavsFolder = faves_coop.get(MEDIA_FAVES_ROOT);
return mediaFavsFolder.hasUnseenItems;
})
// This method has three responsibilities,
// and two entry points.
// First, it ensures that the mediaquery
// contains the most recent 5 RichPhoto items.
// Second, it ensures that RichPhoto items that are being
// Freshly created are marked as "unseen".
// Finally, it does NOT mark them as unseen on first refresh.
// The enum is required to be sorted, newest first
flockPhotoAPIManager.prototype.processPhotoStream =
function photoAPI_processPhotoStream(aUrn, aEnum, bMarkUnseen)
{
var MAX_MEDIAQUERY_CHILDREN = 5;
var faves_coop = Components.classes['@flock.com/singleton;1']
.getService(Components.interfaces.flockISingleton)
.getSingleton("chrome://flock/content/common/load-faves-coop.js")
.wrappedJSObject;
var myStream = faves_coop.get(aUrn);
if (!myStream || this.processingQueue[aUrn]) {
return;
}
this.processingQueue[aUrn] = true;
// JMC - Pruning run, save to destroy children later
var myStreamEnum = myStream.children.enumerateBackwards();
var oldChildren = [];
while (myStreamEnum.hasMoreElements())
{
var child = myStreamEnum.getNext();
if (child) {
oldChildren.push(child);
myStream.children.remove(child);
}
}
var biggestSeq = myStream.latestSeq;
var latestDate = myStream.latestDate;
var inst = this;
var photoIndex = 1;
var newContent = false;
function myWorker(shouldYield) {
while (aEnum.hasMoreElements() && photoIndex <= MAX_MEDIAQUERY_CHILDREN) {
var photo = aEnum.getNext();
photo.QueryInterface(Components.interfaces.flockIPhoto);
// For streams with no uploadDate, we use now. Is that good?
var photoDate = (photo.uploadDate) ? new Date(parseInt(photo.uploadDate)) : new Date();
if (photoDate > latestDate) {
latestDate = photoDate;
biggestSeq = photo.id;
}
var urn = 'urn:flock:item:photo:'+myStream.service+':'+photo.id;
var photoFav;
photoFav = faves_coop.get(urn);
var alreadyIn = (photoFav != null);
if (!alreadyIn) {
newContent = true;
}
// if it doesn't exist, create it
if (!photoFav) {
photoFav = new faves_coop.RichPhoto(urn, {
datevalue: photoDate,
URL: photo.webPageUrl,
thumbnail: photo.thumbnail,
cachedThumbnail: "",
is_public: photo.is_public,
is_video: photo.is_video,
midSizePhoto: photo.midSizePhoto,
name: photo.title,
username: photo.username,
userid: photo.userid,
photoid: photo.id,
largeSizePhoto: photo.largeSizePhoto
});
// add new photostream to myworld service queue
var myworldService = Cc[MYWORLD_SERVICE_CONTRACTID].getService(Ci.flockIMyworldService);
myworldService.queueResource(urn);
}
myStream.children.addOnce(photoFav);
if (!myStream.firstRefresh && !alreadyIn && bMarkUnseen) {
photoFav.unseen = true;
}
photoIndex++;
if (shouldYield()) yield;
}
// if the old children aren't new children, and they're orphans, then destroy them
for(var i =0; i < oldChildren.length; i++)
{
var child = oldChildren[i];
if (child.getParents().length < 1)
{
child.destroy();
}
}
// If we added a newer photo
if (newContent) {
myStream.latestSeq = biggestSeq;
myStream.latestDate = latestDate;
if (!myStream.firstRefresh && bMarkUnseen) {
// JMC - Shouldn't this propagate?
myStream.hasUnseenItems = true;
var parent = myStream.getParent();
if (parent)
{
parent.hasUnseenItems = true;
}
}
}
myStream.firstRefresh = false;
if (myStream.latestDate != latestDate) {
myStream.latestDate = latestDate;
}
inst.processingQueue[aUrn] = false;
}
schedule(0.3, 30, myWorker);
}
flockPhotoAPIManager.prototype.refresh = function(aUrn, aListener) {
var faves_coop = Components.classes['@flock.com/singleton;1']
.getService(Components.interfaces.flockISingleton)
.getSingleton("chrome://flock/content/common/load-faves-coop.js")
.wrappedJSObject;
var photoAPIManager = this;
var listener = function(aStream, aSearchListener) {
this.mStream = aStream;
this.mListener = aSearchListener;
}
var myStream = faves_coop.get(aUrn);
if (!myStream) {
aListener.onError();
return;
}
listener.prototype.onSearchResult = function(aEnum) {
photoAPIManager.processPhotoStream(aUrn, aEnum, true);
this.mListener.onResult(null, null);
};
listener.prototype.onError = function(aError) {
photoAPIManager.mLogger.error(aError);
if(this.mListener) this.mListener.onError(aError);
};
var theApi = this.getAPIFromShortname(myStream.service);
if (!theApi) {
aListener.onResult(null, null);
return;
}
theApi.search(new listener(myStream, aListener), myStream.query, 5, null);
return;
}
flockPhotoAPIManager.prototype.flags = nsIClassInfo.SINGLETON;
flockPhotoAPIManager.prototype.classDescription = "Flock Photo People Service";
flockPhotoAPIManager.prototype.getInterfaces = function (count) {
var interfaceList = [Components.interfaces.flockISocialWebService, flockIPhotoAPIManager, flockIPollingService,
flockIMigratable, nsIClassInfo];
count.value = interfaceList.length;
return interfaceList;
}
flockPhotoAPIManager.prototype.getHelperForLanguage = function (count) {return null;}
// JMC - Making this a social photo service for the preview stream
flockPhotoAPIManager.prototype.QueryInterface =
function (iid) {
if (!iid.equals(Components.interfaces.flockISocialWebService) &&
!iid.equals(flockIPhotoAPIManager) &&
!iid.equals(flockIPollingService) &&
!iid.equals(flockIMigratable) &&
!iid.equals(nsIClassInfo) &&
!iid.equals(nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
// Module implementation
var PhotoPeopleModule = new Object();
PhotoPeopleModule.registerSelf =
function (compMgr, fileSpec, location, type)
{
compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
compMgr.registerFactoryLocation(FLOCK_PHOTO_API_MANAGER_CID,
"Flock Photo API Manager JS Component",
FLOCK_PHOTO_API_MANAGER_CONTRACTID,
fileSpec,
location,
type);
var catman = Components.classes['@mozilla.org/categorymanager;1']
.getService(Components.interfaces.nsICategoryManager);
catman.addCategoryEntry('flockMigratable', 'photoservice', FLOCK_PHOTO_API_MANAGER_CONTRACTID, true, true);
}
PhotoPeopleModule.getClassObject =
function (compMgr, cid, iid) {
if (!cid.equals(FLOCK_PHOTO_API_MANAGER_CID))
throw Components.results.NS_ERROR_NO_INTERFACE;
if (!iid.equals(Components.interfaces.nsIFactory))
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
return PhotoAPIManagerFactory;
}
PhotoPeopleModule.canUnload =
function(compMgr)
{
return true;
}
/* factory object */
var PhotoAPIManagerFactory = new Object();
PhotoAPIManagerFactory.createInstance =
function (outer, iid) {
if (outer != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
return (new flockPhotoAPIManager()).QueryInterface(iid);
}
/* entrypoint */
function NSGetModule(compMgr, fileSpec) {
return PhotoPeopleModule;
}
// a utility for async scheduling:
// cheap scheduler for javascript tasks
// aSlice is the maximum timeslice in seconds. 0.5 or less is a good value
// aPercent is the percent of wall-clock time that should be spent executing
// the task - eg: 20 = one fifth of the time
// aTask is defined to be a generator taking an function that evaluates
// to true if it should yield like:
// function task (should_yield) {
// while (some_condition) {
// do some work...
// if (should_yield()) yield;
// }
// }
// NOTE: should_yield() is fairly cheap but in a tight inner loop it might
// make sense to call it every N cycles
var timers = [];
function schedule (aSlice, aPercent, aTask) {
// convert percent to ratio
var ratio = aPercent / 100.0;
// convert slice to milliseconds
var slice = aSlice * 1000.0;
function milliseconds () { return (new Date ()).getTime (); }
var wall_start = milliseconds ();
var process_time = 0;
var process_start = 0;
function should_yield () {
var now = milliseconds ();
var so_far = now - process_start;
var wall_time = now - wall_start;
return so_far >= slice || ((wall_time * ratio) < (process_time + so_far));
}
var generator = aTask (should_yield);
var timer = Components.classes['@mozilla.org/timer;1']
.createInstance (Components.interfaces.nsITimer);
var callback = {
notify: function () {
var wall_time = milliseconds () - wall_start;
if ((wall_time * ratio) < process_time) {
// if we've spent more time than we're supposed to
// don't run this cycle
}
process_start = milliseconds ();
try {
generator.next ();
} catch (err if err instanceof StopIteration) {
// the task is complete
timer.cancel ();
for (var i=0; i<timers.length; i++) {
if (timers[i] == timer) {
timers.splice (i,1);
}
}
timer = null;
}
process_time += (milliseconds () - process_start);
}
}
timer.initWithCallback (callback, Math.round (slice/ratio),
Components.interfaces.nsITimer.TYPE_REPEATING_SLACK)
timers.push (timer);
}